package semant.first_pass;

import util.List;
import semant.Env;
import symbol.Symbol;
import symbol.ClassInfo;
import symbol.MethodInfo;
import syntaxtree.MethodDecl;
import syntaxtree.VarDecl;
import syntaxtree.Formal;
import syntaxtree.Statement;
import syntaxtree.Type;
import syntaxtree.VisitorAdapter;

final class MethodDeclHandler extends VisitorAdapter {

    private Env env;
    private ClassInfo cinfo;

    private MethodDeclHandler(Env e, ClassInfo c){
	super();
	env = e;
	cinfo = c;
    }

    static void firstPass(Env e, ClassInfo c, MethodDecl md){
	MethodDeclHandler h = new MethodDeclHandler(e, c);
	md.accept(h);
    }

    public void visit(MethodDecl node){
    	Type t = node.returnType;
    	Symbol name = Symbol.symbol(node.name.s);
    	
    	MethodInfo minfo = new MethodInfo(t, name, cinfo.name);

	// insere lista de parametros do metodo na tabela
	for(List<Formal> f = node.formals; f != null; f = f.tail)
	    FormalHandler.firstPass(env, cinfo, minfo, f.head);

	// insere lista de variaveis locais na tabela
	for(List<VarDecl> vd = node.locals; vd != null; vd = vd.tail)
	    VarDeclHandler.firstPass(env, cinfo, minfo, vd.head);

    	if(!cinfo.addMethod(minfo)){
	    MethodInfo old = cinfo.methods.get(name);

	    if(old == null) throw new Error(); //Ver mensagem a ser atribuida

	    env.err.Error(node, new Object[]{"Metodo \'" + name + "' previamente declarado na classe '" + cinfo.name + "' aqui: [" + old.type.line + "," + old.type.row + "]"});
    	}
    }

}
